﻿//------------------------------------------------------------------------------
// <copyright file="RpcBinaryData.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace Microsoft.Internal.GamesTest.Rpc.Client
{
    using System;
    using System.Runtime.Serialization;
    using System.Text;

    /// <summary>
    /// This class is the data container used to send and receive binary data to and 
    /// from an RpcServer.
    /// </summary>
    [Serializable]
    public class RpcBinaryData : ISerializable
    {
        private byte[] binaryData;

        /// <summary>
        /// Initializes a new instance of the RpcBinaryData class.
        /// </summary>
        public RpcBinaryData()
        {
            this.binaryData = new byte[0];
            this.Encoding = RpcBinaryToTextEncoding.Base64;
        }

        /// <summary>
        /// Initializes a new instance of the RpcBinaryData class.
        /// </summary>
        /// <param name="data">The byte[] to use as the data.</param>
        public RpcBinaryData(byte[] data)
        {
            this.binaryData = data;
            this.Encoding = RpcBinaryToTextEncoding.Base64;
        }

        /// <summary>
        /// Initializes a new instance of the RpcBinaryData class.
        /// This constructor is implicitly required by the ISerializable interface.
        /// </summary>
        /// <param name="information">The System.Runtime.Serialization.SerializationInfo to use to populate the new RpcBinaryData.</param>
        /// <param name="context">The source (see System.Runtime.Serialization.StreamingContext) for this deserialization.</param>
        protected RpcBinaryData(SerializationInfo information, StreamingContext context)
            : this()
        {
            if (information == null)
            {
                throw new ArgumentNullException("information");
            }

            this.Encoding = (RpcBinaryToTextEncoding)information.GetValue("encoding", typeof(int));
            this.Compression = (RpcCompressionScheme)information.GetValue("compression", typeof(int));

            this.DecodeData((string)information.GetValue("data", typeof(string)));
        }

        /// <summary>
        /// Gets or sets the binary to text encoding scheme used to encode the data.
        /// </summary>
        internal RpcBinaryToTextEncoding Encoding { get; set; }

        /// <summary>
        /// Gets or sets the compression scheme used to compress the data.
        /// </summary>
        internal RpcCompressionScheme Compression { get; set; }

        /// <summary>
        /// Gets binary data.
        /// </summary>
        /// <returns>The byte[] data for this object.</returns>
        public byte[] GetData()
        {
            return this.binaryData;
        }

        /// <summary>
        /// Sets binary data.
        /// </summary>
        /// <param name="data">The data to set.</param>
        public void SetData(byte[] data)
        {
            this.binaryData = data;
        }

        /// <summary>
        /// Populates a System.Runtime.Serialization.SerializationInfo with the data needed to serialize this object.
        /// </summary>
        /// <param name="info">The System.Runtime.Serialization.SerializationInfo to populate with data.</param>
        /// <param name="context">The destination (see System.Runtime.Serialization.StreamingContext) for this serialization.</param>
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            this.GetObjectData(info, context);
        }

        /// <summary>
        /// Encodes this objects data.
        /// </summary>
        /// <returns>The encoded string.</returns>
        internal string EncodeData()
        {
            string encodedData;
            byte[] compressedData = this.binaryData;
            switch (this.Compression)
            {
                case RpcCompressionScheme.None:
                default:
                    break;
            }

            switch (this.Encoding)
            {
                case RpcBinaryToTextEncoding.Base64:
                default:
                    encodedData = Convert.ToBase64String(compressedData);
                    break;
            }

            return encodedData;
        }

        /// <summary>
        /// Decodes the data.
        /// </summary>
        /// <param name="value">The encoded string to decode.</param>
        internal void DecodeData(string value)
        {
            byte[] data;

            switch (this.Encoding)
            {
                case RpcBinaryToTextEncoding.Base64:
                default:
                    data = Convert.FromBase64String(value);
                    break;
            }

            switch (this.Compression)
            {
                case RpcCompressionScheme.None:
                default:
                    break;
            }

            this.binaryData = data;
        }

        /// <summary>
        /// An overload of the GetObjectData method that is required by the ISerializable interface.
        /// This is here so that inheritors of this class can access the GetObjectData method without
        /// having to cast their "this" pointer to an ISerializable.
        /// Populates a System.Runtime.Serialization.SerializationInfo with the data needed to serialize this object.
        /// </summary>
        /// <param name="info">The System.Runtime.Serialization.SerializationInfo to populate with data.</param>
        /// <param name="context">The destination (see System.Runtime.Serialization.StreamingContext) for this serialization.</param>
        protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }

            info.AddValue("encoding", this.Encoding);
            info.AddValue("compression", this.Compression);
            info.AddValue("data", this.EncodeData());
        }
    }
}